﻿//用于基础运算处理
//本文件由：贺镇涛（2021300004071）负责
#include"Mathtoys.h"
#include"BasicToys.h"
#include"FunctionStoreHouse.h"
#include"QuantityStorehouse.h"
#include"CommandStoreHouse.h"
static QuantityStoreHouse QuantityContainer;	//需要修改，调用周博儒的.my类导入常量集
static CommandStoreHouse CommandContainer;		//需要修改，调用周博儒的.my类导入命令集
static FunctionStoreHouse FunctionContainer;	//需要修改，调用周博儒的.my类导入函数集

string basic(string s)
{
	if (s.back() != '=')
	{
		s += "=";
	}
	pre_handle(s);						//预处理
	vector<string> str_cut = cutter(s); //切片
	if (IsCommand(str_cut[0]))			//如果是命令，未完成
	{
		str_cut.pop_back();				//去除等号
		if (str_cut[0] == "def" && str_cut.size() >= 3)		//define
		{
			if (str_cut.size() >= 4) cout << "当前版本一行只能修改一个变量，其余修改将被舍弃！\n";
			if (QuantityContainer.isInlist(str_cut[1]))
			{
				string old = QuantityContainer.get_value(str_cut[1]);
				*QuantityContainer.get_valuePTR(str_cut[1]) = str_cut[2];
				return "已修改:" + str_cut[1] + "=" + QuantityContainer.get_value(str_cut[1]) + ",原值为" + old;
			}
			else {
				QuantityContainer.addToTail(str_cut[1], str_cut[2]);
				return "已定义:" + str_cut[1] + "=" + QuantityContainer.get_value(str_cut[1]);
			}
		}
		else if (str_cut[0] == "undef" && str_cut.size() == 2) 
		{
			if (!QuantityContainer.isInlist(str_cut[1])) { return str_cut[1]+"未定义"; }
			else {
				QuantityContainer.deleteNode(str_cut[1]);
				return "已删除" + str_cut[1];
			}
		}
		else if (str_cut[0] == "fdef" && str_cut.size() >= 5)		//define function
		{//fdef f(x)=x+y+z
			string new_func = "";
			for (int i=6;i<=str_cut.size()-1;i++)
			{
				new_func += str_cut[i];
			}
			Replace_All(new_func,str_cut[3], "x");
			if (FunctionContainer.isInlist(str_cut[1]))
			{
				string old = *FunctionContainer.get_valuePTR(str_cut[1]);
				*FunctionContainer.get_valuePTR(str_cut[1]) = new_func;
				return 
					"已修改:" + str_cut[1] + "=" + *FunctionContainer.get_valuePTR(str_cut[1]) + ",原函数为" + old;
			}
			else {
				FunctionContainer.addToTail(str_cut[1], new_func);
				return "已定义:" + str_cut[1] + "=" + *FunctionContainer.get_valuePTR(str_cut[1]);
			}
		}
		else if (str_cut[0] == "fundef" && str_cut.size() >= 2)
		{
			if (!FunctionContainer.isInlist(str_cut[1])) { return str_cut[1] + "未定义"; }
			else {
				FunctionContainer.deleteNode(str_cut[1]);
				return "已删除" + str_cut[1];
			}
		}
		else return str_cut[0]+":语法错误";
	}
	else											//一般运算
	{
		string out = cal(str_cut);			//运算
		return out;							//输出
	}
}

void pre_handle(string& s) //实现表达式最开始的正负数：转化为0+-
{
	for (size_t i = 0; i < s.size(); i++)
	{
		if (i == 0 && (s[i] == '-' || s[i] == '+')) { s.insert(0, 1, '0'); }
		if (s[i] == '(' && (s[i + 1] == '-' || s[i + 1] == '+')) { s.insert(i + 1, 1, '0'); }
	}
}

inline bool IsOper(string s)		//判断是否是操作符
{
	if (s == "+" || s == "-" ||
		s == "*" || s == "/" ||
		s == "=" || s == "^" ||
		s == "(" || s == ")" ||
		s == "[" || s == "]" ||
		s == "{" || s == "}")
	{
		return 1;
	}
	else return 0;
}

inline bool IsOper(char s)		//判断是否是操作符
{
	if (s == '+' || s == '-' ||
		s == '*' || s == '/' ||
		s == '=' || s == '^' ||
		s == '(' || s == ')' ||
		s == '[' || s == ']' ||
		s == '{' || s == '}' || s == ' ')
	{
		return 1;
	}
	else return 0;
}

bool IsCommand(const string& s)
{
	if (s == "def"||s=="undef") return 1;
	else if (s == "fdef"||s=="fundef") return 1;
	else return CommandContainer.isInlist(s);
}

//将输入string切片储存在vector中
vector<string> cutter(string s)
{
	vector<string> str_cut;
	size_t end_point = 0;//切片终点
	size_t i = 0;
	while (i < s.length())
	{
		if (IsOper(s[i]))
		{
			end_point = i;										//更改切片的终点
			if (i != 0)str_cut.push_back(s.substr(0, end_point)); 			//载入前操作数	
			if (s[i] != ' ')
			{
				str_cut.push_back(string(1, s[end_point]));	//载入运算符
			}
			if (s[i + 1] != ' ') //留下后方切片
			{
				s = s.substr(end_point + 1);
			}
			else if (s[i + 1] == ' ')
			{
				s = s.substr(end_point + 2);
			}
			i = 0;
			continue;
		}
		i++;
	}
	if (s != "") { str_cut.push_back(s); }				//载入结尾
	return str_cut;
}

inline bool CanCal(const vector<string>& CalStack, const int i, const vector<string>& str_cut)	//可以直接计算
{
	size_t size = CalStack.size();
	string temp = CalStack.back();
	size_t tmp = i;
	if (tmp - 1 == str_cut.size()) return 1;
	else if (
		(
			CalStack.size() >= 3
			&& str_cut.size() >= 3
			&& !IsOper(temp) && IsOper(CalStack[size - 2]) && !IsOper(CalStack[size - 3])
			&& (get_pri(CalStack[size - 2]) >= get_pri(str_cut[tmp + 1])))
		|| temp == "!"
		)
		return 1;
	else return 0;
}

string cal(vector<string> str_cut)
{
	vector<string> CalStack;			//用向量模拟栈，为的是能够访问非栈顶元素(取舍：为了不想引入第二个符号栈)....（无奈）
	string u;
	for (int i = 0; i <= str_cut.size() - 1; i++)
	{
		u = str_cut[i];
		if (u == "(" || u == "[" || u == "{")
		{

			string Prev = "+";//默认为加号
			if (i >= 1)	 Prev = str_cut[size_t(i) - 1];//括号前的数，判断是符号还是函数

			string result;					//递归获得结果
			string call_input = "";
			int IsOdd = 1;						//用于储存括号的奇偶
			int t = i + 1;
			for (; t <= str_cut.size() - 1; t++)
			{
				if ((str_cut[t] == ")" || str_cut[t] == "]" || str_cut[t] == "}") && IsOdd == 1)
				{
					IsOdd--;
				}
				else
				{
					call_input += str_cut[t];
					if (str_cut[t] == "(" || str_cut[t] == "[" || str_cut[t] == "{")
					{
						IsOdd++;
					}
					else if (str_cut[t] == ")" || str_cut[t] == "]" || str_cut[t] == "}")
					{
						IsOdd--;
					}
				}
				if (IsOdd == 0)
				{
					if (IsOper(Prev)) call_input += "=";//如果括号前是运算符，那么加上等号，用basic运算
					break;
				}
			}
#if _DEBUG
			//cout << call_input;				//这里已经没有问题了
#endif
			if (IsOper(Prev)) result = basic(call_input);
			else result = Call_Function(Prev, call_input);//调用Prev所指定的函数处理call_input
#if _DEBUG
			//cout << result << "t=" << t << endl;
#endif			
			CalStack.push_back(result);
#if _DEBUG
			//cout << CalStack.back();
#endif
			i = t;
		}
		else if (u != "=") { 
			if (QuantityContainer.isInlist(u)) CalStack.push_back(QuantityContainer.get_value(u));
			else if (FunctionContainer.isInlist(u)) { 
				string variate=str_cut[size_t(i)+2];				//实参变量
				i = i + 3;
				CalStack.push_back(FunctionContainer.get_value(u,variate)); }
			else CalStack.push_back(u);
		}
		while (CanCal(CalStack, i, str_cut)) //可以计算就一直计算下去，直到不能计算为止
		{
#if _DEBUG
			//cout << CalStack[CalStack.size() - 2]<<"Is this working? ";
#endif
			if (CalStack[CalStack.size() - 2] == "+")
			{
				CalStack[CalStack.size() - 3] = StringPlus(CalStack[CalStack.size() - 3], CalStack.back());
			}
			else if (CalStack[CalStack.size() - 2] == "-")
			{
				CalStack[CalStack.size() - 3] = StringMinus(CalStack[CalStack.size() - 3], CalStack.back());
			}
			else if (CalStack[CalStack.size() - 2] == "*")
			{
				CalStack[CalStack.size() - 3] = StringMulty(CalStack[CalStack.size() - 3], CalStack.back());
			}
			else if (CalStack[CalStack.size() - 2] == "/")
			{
				CalStack[CalStack.size() - 3] = StringDiv(CalStack[CalStack.size() - 3], CalStack.back());
			}
			else if (CalStack[CalStack.size() - 2] == "^")
			{
				CalStack[CalStack.size() - 3] = StringPow(CalStack[CalStack.size() - 3], CalStack.back());
			}
			else if (CalStack.back() == ")" || CalStack.back() == "]" || CalStack.back() == "}")
			{
				CalStack[CalStack.size() - 3] = CalStack[CalStack.size() - 2];
			}
			CalStack.pop_back();
			CalStack.pop_back();//弹出最后两个元素，完成一次运算
		}
	}
	u.~basic_string();
	return CalStack.back();
}

string Call_Function(const string& FuncName, const string& s)
{
	string(*handle)(const string & input) = NULL;//函数指针，为以后的调用做准备
	if (FuncName == "Sin");
	else if (FuncName == "Cos");
	else if (FuncName == "Tan");
	else if (FuncName == "Cot");
	else if (FuncName == "Acos");
	else if (FuncName == "Asin");
	else if (FuncName == "Atan");
	else handle = &SF_Show;
	return (*handle)(s);
}

inline int get_pri(string oper)//获得优先级//保留
{
	if (oper == "+" || oper == "-")
	{
		return 1;
	}
	else if (oper == "*" || oper == "/")//乘除法的优先级为2
	{
		return 2;
	}
	else if (oper == "%" || oper == "^")//取余乘方的优先级为3
	{
		return 3;
	}
	else if (oper == "！")//阶乘4
	{
		return 4;
	}
	else
	{
		return 0;//其余为0
	}
}

string& Replace_All(string& str_old, const string& old_value, const string& new_value) {
	for (string::size_type pos(0); pos != string::npos; pos += new_value.length()) {
		if ((pos = str_old.find(old_value, pos)) != string::npos) {
			str_old.replace(pos, old_value.length(), new_value);
		}
		else break;
	}
	return str_old;
}
